package com.wangjiang.foundation.mybatis.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wangjiang.foundation.common.exception.CommonException;
import com.wangjiang.foundation.common.util.ClassUtil;
import com.wangjiang.foundation.common.util.CommonUtils;
import com.wangjiang.foundation.mybatis.entity.BaseEntity;
import com.wangjiang.foundation.mybatis.entity.BaseListRet;
import com.wangjiang.foundation.mybatis.entity.BasePageListRet;
import com.wangjiang.foundation.mybatis.entity.BaseVO;
import com.wangjiang.foundation.mybatis.params.IdList;
import com.wangjiang.foundation.mybatis.params.QueryParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Transactional(rollbackFor = Exception.class)
public class CurdServiceImpl<M extends BaseMapper<T>, T extends BaseEntity, V extends BaseVO> extends ServiceImpl<M, T>
        implements CurdService<T, V> {

    private static final Logger logger = LoggerFactory.getLogger(CurdServiceImpl.class);

    @Override
    public BaseListRet<V> getList(QueryParams queryParams) {
        if (queryParams.isPaging()) {
            return getPage(queryParams);
        } else {
            List<T> list = list(createQuery(queryParams));
            List<V> collect = list.stream().map(this::entityToModel).collect(Collectors.toList());
            BaseListRet<V> ret = new BaseListRet<>();
            ret.setData(collect);
            return ret;
        }
    }

    private BaseListRet<V> getPage(QueryParams queryParams) {
        IPage<T> page = new Page(queryParams.getPageNo(), queryParams.getPageSize());
        IPage<T> ret = page(page, createQuery(queryParams));
        BasePageListRet<V>  pageListRet = new BasePageListRet<>();
        pageListRet.setPageNo(ret.getCurrent());
        pageListRet.setPageSize(ret.getSize());
        pageListRet.setTotal(ret.getTotal());
        pageListRet.setTotalPages(ret.getPages());
        pageListRet.setData(ret.getRecords().stream().map(this::entityToModel).collect(Collectors.toList()));
        return pageListRet;
    }

    private T  modelToEntity(V model) {
        T entity = (T) model.convertTo();
        return entity;
    }

    public V entityToModel(T entity) {
        V vo = createVoInstance();
        return (V) vo.convertFrom(entity);
    }

    @Override
    public V getByUuid(String uuid) {
        T entity = getOne(createQuery().eq("uuid", uuid));
        V vo = createVoInstance();
        return (V) vo.convertFrom(entity);
    }

    public V getById(Long id) {
        T entity = getOne(createQuery().eq("id", id));
        V vo = createVoInstance();
        return (V) vo.convertFrom(entity);
    }


    public T getOne(Wrapper<T> queryWrapper) {
        T entity = super.getOne(queryWrapper);
        if (CommonUtils.isNull(entity)) {
            throw new CommonException("data is null");
        }
        return entity;
    }


    @Override
    public V createVoInstance() {
        Class type = ClassUtil.getGenericType(getClass(), 2);
        try {
            return (V) type.newInstance();
        } catch (Exception e) {
            // Oops, no default constructor
            throw new CommonException(e);
        }
    }

    @Override
    public T createEntity() {
        Class type = ClassUtil.getGenericType(getClass(), 1);
        try {
            return (T) type.newInstance();
        } catch (Exception e) {
            // Oops, no default constructor
            throw new CommonException(e);
        }
    }

    /**
     * Todo
     *
     * @author wangjiang
     * @date 2021-01-02 11:24:08
     * @return
     */
    @Override
    public boolean update(String id, T entity) {
        entity.setUuid(id);
        return updateById(entity);
    }

    @Override
    public Boolean patch(String id, T modelToEntity) {
        return update(id, modelToEntity);
    }

    @Override
    public boolean saveOrUpdate(T modelToEntity) {
        return super.saveOrUpdate(modelToEntity);
    }

    @Override
    public boolean insert(T modelToEntity) {
        return save(modelToEntity);
    }

    @Override
    public boolean delete(String id) {
        return super.removeById(id);
    }

    @Override
    public Boolean deleteByIds(IdList ids) {
        if (CommonUtils.isNull(ids.getIdList())) {
            return false;
        }
        return remove(createQuery().in("id",  ids.getIdList()));
    }

    private QueryWrapper<T> createQuery() {
        return new QueryWrapper<T>();
    }


        private Wrapper<T> createQuery(QueryParams queryParams) {
        QueryWrapper<T> query = createQuery();
        return queryParams.build(query);
    }
}
